﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Media;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Diagnostics;
using System.IO;
#endregion using

namespace CakeRaid
{
    // This class should never be created, rather only children classes (thus abstract)
    abstract class Tower : GameObject
    {
        #region Attributes
        protected bool placing, canFire;
        protected Tile_Tower occupiedTile;
        
        protected Random rand;
        protected int cost, upgradeLevel;
        protected float fireRadius, bulletSpeed;
        protected List<Bullet> bullets;
        protected Texture2D bulletTexture;
        protected Var.TowerType type;
        protected List<Enemy> enemiesInRange;

        //includes all behaviors for all towers
        public enum BehaviorState { Fire, Search, Wait, Upgrade }
        protected BehaviorState behavior;

        public enum Attacktype { None, Fastest, Slowest, Strongest, Weakest, First, Last }
        protected Attacktype attackType;
        #endregion Attributes

        #region Constructor
        public Tower(ImageObject io, float fireRadius, int health, int cost, int damage, float speed, float bulletSpeed, Texture2D bt, Attacktype attackType)
            : base(io, health, damage, speed)
        {
            this.attackType = attackType; this.fireRadius = fireRadius; this.bulletSpeed = bulletSpeed;
            canFire = true; placing = true;
            timer = new Timer(); rand = new Random();
            this.cost = cost;
            bulletTexture = bt;
            bullets = new List<Bullet>(); enemiesInRange = new List<Enemy>();
            Image.Transparency = Var.PLACING_TRANSPARENCY;
            upgradeLevel = 0;
            behavior = BehaviorState.Search;
        }
        #endregion Constructor

        #region Properties
        public bool Placing
        {
            get { return placing; }
            set { placing = value; }
        }

        public Tile_Tower OccupiedTile
        {
            get { return occupiedTile; }
            set { occupiedTile = value; }
        }

        public bool CanFire
        {
            get { return canFire; }
            set { canFire = value; }
        }

        public int Cost
        {
            get { return cost; }
            set { cost = value; }
        }

        public int UpgradeLevel
        {
            get { return upgradeLevel; }
            set { upgradeLevel = value; }
        }

        public float BulletSpeed
        {
            get { return bulletSpeed; }
            set { bulletSpeed = value; }
        }

        public float FireRadius
        {
            get { return fireRadius; }
            set { fireRadius = value; }
        }

        public Var.TowerType Type
        {
            get { return type; }
            set { type = value; }
        }

        public Attacktype AttackType
        {
            get { return attackType; }
            set { attackType = value; }
        }
        #endregion Properties

        #region Methods

        public void Update(GameTime gameTime)
        {
            time = gameTime;
            timer.Update(gameTime, Var.GAME_SPEED);
            healthBar.Update(gameTime, CurrentHealth, Center.X, Y);
        }

        #region Update Enemies In Range
        public void UpdateEnemiesInRange(List<Enemy> enemies)
        {
            foreach (Enemy enemy in enemies)
            {
                if ((enemy.Behavior != Enemy.BehaviorState.Death) && (enemy.Behavior != Enemy.BehaviorState.Spawn) && (fireRadius >= Vector2.Distance(enemy.Center, Center)))
                {
                    enemiesInRange.Add(enemy);
                }
            }
        }
        #endregion Update Enemies In Range

        public abstract void Activate();

        public void Place(Tile_Tower tile)
        {
            eventTimer.Start();
            placing = false;
            occupiedTile = tile;
            occupiedTile.OccupiedBy = this;
            Center = tile.Center;
            Image.Transparency = 100;
        }

        //checks bullet collisions and removes bullets if true
        public void CheckBulletCollision(GameObject GO)
        {
            if (GO is Enemy)
            {
                Enemy curEnemy = (Enemy)GO;
                for (int i = 0; i < bullets.Count; i++)
                {
                    if (bullets[i].IsActive)
                    {
                        if (curEnemy.Rectangle.Intersects(bullets[i].Rectangle))
                        {
                            curEnemy.Hit(Damage);
                            bullets.RemoveAt(i);
                            i--;
                        }
                    }
                }
            }
        }

        #region Get Damaged (Hit)
        public void Hit(int hitDmg)
        {
            if (IsActive)
            {
                CurrentHealth =  CurrentHealth - hitDmg;
                healthBar.Show(time);

                if (CurrentHealth <= 0)
                {
                    healthBar.Hide();
                    timer.Start(time, Var.DYING_TIME);
                }
            }
        }
        #endregion Get Damaged (Hit)

        public int SellCost()
        {
            if ((int)(cost * ((float)CurrentHealth / (float)StartHealth) / 2f) > 0)
                return (int)(cost * ((float)CurrentHealth / (float)StartHealth) / 2f);
            else
                return 0;
        }

        /// <summary> If it should be removed, returns itself; else returns null </summary>
        public Tower RemoveIfCan()
        {
            if (CurrentHealth <= 0)
                IsActive = false;

            if (!IsActive)
            {
                occupiedTile.OccupiedBy = null;
                return this;
            }
            return null;
        }
        #endregion Method

        #region Draw
        public virtual void Draw(GameTime gameTime)
        {
            if (IsActive)
            {
                if (CurrentHealth > ((Var.RAD_TOWER_HEALTH / 4) * 3) && CurrentHealth <= Var.RAD_TOWER_HEALTH)
                {
                    base.Draw(0, 0);
                }
                else if (CurrentHealth > ((Var.RAD_TOWER_HEALTH / 4) * 2) && CurrentHealth <= ((Var.RAD_TOWER_HEALTH / 4) * 3))
                {
                    base.Draw(1, 0);
                }
                else if (CurrentHealth > ((Var.RAD_TOWER_HEALTH / 4) * 1) && CurrentHealth <= ((Var.RAD_TOWER_HEALTH / 4) * 2))
                {
                    base.Draw(2, 0);
                }
                else if (CurrentHealth > 0 && CurrentHealth <= ((Var.RAD_TOWER_HEALTH / 4) * 1))
                {
                    base.Draw(3, 0);
                }
                bullets.ForEach(bullet => bullet.Draw(0, 0));
                healthBar.Draw();
            }
        }
        #endregion Draw
    }
}